// ---------------------------------------------------------------------------
// This software is in the public domain, furnished "as is", without technical
// support, and with no warranty, express or implied, as to its usefulness for
// any purpose.
//
// TorrentFile.C
// <brief class description>
//
// Author: wuwei0509@gmail.com
// ---------------------------------------------------------------------------
#include <assert.h>
#include <fstream>
#include <iostream>

#include "TorrentFile.h"
#include "Helper.h"
using namespace std;

TorrentFile::TorrentFile()
:creationDate(0),
 pieceLength(0),
 fileLength(0)
{}

TorrentFile::~TorrentFile()
{
	trackerList.clear();
	createdBy.clear();
	creationDate = 0;
	encoding.clear();
	pieceLength = 0;
	pieces.clear();
	name.clear();
	fileLength = 0;
	files.clear();
}

void TorrentFile::ParseSeedFile(char * fullPath)
{
	ifstream in(fullPath, ios::binary);
	assert(in.is_open() == true);
	//read while file
	__int64 len = 0;
	char * seedContent = NULL;
	//get file len
	in.seekg(0, ios::end);
	len = in.tellg();
	in.seekg(0, ios::beg);
	seedContent = Helper::mallocSpace(len);

	in.read(seedContent, static_cast<int>(len));

	//build the seed file dict(a torrent file is a dict)
	__int64 startPos = 0;
	BencodingData seedFileDict = BuildSeedFileDict(seedContent, startPos);

	delete [] seedContent;
	in.close();
}

void TorrentFile::GenerateSeedFileFromSingleFile(char * file)
{
}

void TorrentFile::GenerateSeedFileFromDirectory(char * dir)
{
}

void TorrentFile::PrintInfo()
{
}

BencodingData TorrentFile::BuildSeedFileDict(char * seedContent, __int64& startPos)
{
	assert(seedContent != NULL);
	assert(startPos >= 0);

	BencodingData ret;
	char beginning = *(seedContent + startPos);//beginning delimiter
	startPos++;
	switch(beginning) {
		//int type
		case 'i': {
			ret.setType(BENCODINGTYPE_INT);
			__int64 value = BencodingHandler::ReadInt(seedContent, --startPos);
			ret.setValue(value);
			return ret;
		}
		//list type
		case 'l': {
			ret.setType(BENCODINGTYPE_LIST);
			while(*(seedContent + startPos) != 'e') {
				BencodingData value = BuildSeedFileDict(seedContent, startPos);
				ret.getListValue().push_back(value);
			}
			startPos++;
			return ret;
		}
		//dict type
		case 'd': {
			ret.setType(BENCODINGTYPE_DICT);
			while(*(seedContent + startPos) != 'e') {
				//get key
				string key = BencodingHandler::ReadString(seedContent, startPos);
				//get value
				BencodingData value = BuildSeedFileDict(seedContent ,startPos);

				DictPair pair(key, value);
				ret.getDictValue().push_back(pair);
			}
			startPos++;
			return ret;
		}
		//byte string type
		case '0': case '1': case '2': case '3':
		case '4': case '5': case '6': case '7':
		case '8': case '9': {
			ret.setType(BENCODINGTYPE_STRING);
			string value = BencodingHandler::ReadString(seedContent, --startPos);
			ret.setValue(value);
			return ret;
		}
		//unknown type
		default: {
			cerr<<"Error: Confront unknown BencodingData type"<<endl;
			exit(1);
		}
	}//switch
}